import pygame #imports the pygame library for use
from pygame.locals import * #imports some constants from pygame to make our lives a bit easier
import random #import the random library for generating random numbers
import math #To do some more complexish math

#Initialize random pygame stuff
pygame.init()
#Create a window to draw in
WINDOW_SIZE = WINDOW_WIDTH,WINDOW_HEIGHT = 640, 400
window = pygame.display.set_mode(WINDOW_SIZE)
#Create the clock to limit framerate
clock = pygame.time.Clock()
FRAMERATE = 30
#Set constants and global variables
PLAYER_PADDLE_SPEED = 20
AI_PADDLE_SPEED = 8
SCORE1 = 0
SCORE2 = 0
MAXSCORE = 5 #Points required to win a game
BALL_START_SPEED = 10

class Ball:
	"""This will be the ball that moves and bounces."""
	def __init__(self):
		"""Initialize the ball."""
		#Create the variables for the position and speed of the ball. They will be changed in reset()
		self.x = 0
		self.y = 0
		self.xspeed = 0
		self.yspeed = 0
		
		self.radius = 12
		
		#Set the ball's position and speed 
		self.reset()
	def update(self):
		"""Called every frame to handle movement."""
		#Move the ball based on its speed
		self.x += self.xspeed
		self.y += self.yspeed
		
		#Bounce
		#Top and bottom
		if self.y-self.radius <= 0 or self.y+self.radius >= WINDOW_HEIGHT:
			self.yspeed *= -1
		#Off the paddles (The tricky one
		if self.x - self.radius - paddle1.width <= 0: #left paddle
			if abs(paddle1.y - self.y) <= paddle1.height/2 + self.radius:
				self.xspeed *= -1
				self.xspeed += math.copysign(1,self.xspeed)
				self.yspeed = (((self.y-paddle1.y)/4+self.yspeed)/2)*(math.sqrt(abs(self.xspeed)/BALL_START_SPEED))
			else:
				score(2)
		if self.x + self.radius + paddle2.width >= WINDOW_WIDTH: #right paddle
			if abs(paddle2.y - self.y) <= paddle2.height/2 + self.radius:
				self.xspeed *= -1
				self.xspeed += math.copysign(1,self.xspeed)
				self.yspeed = (((self.y-paddle2.y)/4+self.yspeed)/2)*(math.sqrt(abs(self.xspeed)/BALL_START_SPEED))
			else:
				score(1)
	def draw(self):
		"""Called every frame. Draws the ball in the window."""
		pygame.draw.circle(window, (255,255,255), (int(self.x),int(self.y)), self.radius, 0)
	def reset(self):
		"""Called after a point is scored and at the beginning of the game. Resets the ball to the middle of the screen."""
		self.x = WINDOW_WIDTH/2
		self.y = WINDOW_HEIGHT/2
		
		self.xspeed = (random.randint(0,1)*2-1)*BALL_START_SPEED
		self.yspeed = random.uniform(-5,5)

class Paddle:
	"""This will be a paddle that is either computer or human controlled."""
	def __init__(self, player, AI):
		"""Initialize the paddle. player is either 1 (left) or 2 (right). AI is True or False."""
		self.player = player
		self.AI = AI
		self.y = 0
		self.width = 16 #Horizontal
		self.height = 128 #Verticle
		self.reset()
	def update(self):
		"""Called every frame to handle data stuff."""
		if self.AI:
			#Do AI stuff
			for i in range(AI_PADDLE_SPEED):
				if self.y < ball.y:
					self.y += 1
				elif self.y > ball.y:
					self.y -= 1
				else:
					break
		else:
			#Recieve player control
			if keys[K_UP]:
				self.y -= PLAYER_PADDLE_SPEED
			if keys[K_DOWN]:
				self.y += PLAYER_PADDLE_SPEED
	def draw(self):
		"""Called every frame. Draws the paddle in the window."""
		if self.player == 1:
			pygame.draw.rect(window, (255,255,255), (0,self.y-self.height/2,self.width, self.height),0)
		else:
			pygame.draw.rect(window, (255,255,255), (WINDOW_WIDTH-self.width,self.y-self.height/2,self.width, self.height),0)
	def reset(self):
		"""Called after a point is scored. Resets the paddle to the center position."""
		self.y = WINDOW_HEIGHT/2 #sets y to center of the screen

def score(player):
	"""Called when a player scores."""
	global SCORE1, SCORE2
	if player == 1:
		SCORE1 += 1
		if SCORE1 >= MAXSCORE:
			drawText(window, "PLAYER 1 WINS", "c", fonts[2], (255,255,255))
			pygame.display.flip()
			pygame.time.wait(2000)
			newGame()
			return
	elif player == 2:
		SCORE2 += 1
		if SCORE2 >= MAXSCORE:
			drawText(window, "PLAYER 2 WINS", "c", fonts[2], (255,255,255))
			pygame.display.flip()
			pygame.time.wait(2000)
			newGame()
			return
	ball.reset()
	paddle1.reset()
	paddle2.reset()
	
	#Draw while waiting
	ball.draw()
	paddle1.draw()
	paddle2.draw()
	pygame.draw.line(window, (255,255,255), (WINDOW_WIDTH/2,0),(WINDOW_WIDTH/2,WINDOW_HEIGHT))
	drawText(window, str(SCORE1), (WINDOW_WIDTH/2 + 8,WINDOW_HEIGHT/2 - fonts[1].size(str(SCORE1))[1]/2), fonts[1])
	drawText(window, str(SCORE2), (WINDOW_WIDTH/2 - fonts[0].size(str(SCORE2))[1]-8,WINDOW_HEIGHT/2 - fonts[1].size(str(SCORE2))[1]/2), fonts[1])
	pygame.display.flip()
	#Wait
	pygame.time.wait(300)
def drawText(targetSurface, text, pos, font, color = (255,255,255)):
	"""Draws text on the targetSurface at pos in font and color. Defaults to black. If pos is "c", text drawn at center of surface"""
	if pos != "c":
		text = font.render(text, True, color)
		targetSurface.blit(text, pos)
	else:
		width,height = font.size(text)
		surfaceWidth, surfaceHeight = targetSurface.get_size()
		text = font.render(text, True, color)
		targetSurface.blit(text, (surfaceWidth/2-width/2,surfaceHeight/2-height/2))
def newGame(AI1 = None, AI2 = None):
	"""Starts a new game"""
	global SCORE1, SCORE2
	SCORE1 = 0
	SCORE2 = 0
	if AI1 != None:
		paddle1.AI = AI1
	if AI2 != None:
		paddle2.AI = AI2
	paddle1.reset()
	paddle2.reset()
	ball.reset()
	
	window.fill((0,0,0))
	pygame.draw.line(window, (255,255,255), (WINDOW_WIDTH/2,0),(WINDOW_WIDTH/2,WINDOW_HEIGHT))
	paddle1.draw()
	paddle2.draw()
	drawText(window, "GO", "c", fonts[2], (255,255,255))
	pygame.display.flip()
	pygame.time.wait(1000)
####Set the level
#Create paddles
paddle1 = Paddle(1, False) #Human
paddle2 = Paddle(2, True) #AI
#Create ball
ball = Ball()
#Keys
keys = [] #the list for storing key values
for i in range(512):
	keys.append(False)
#Create Fonts
fonts = []
fonts.append(pygame.font.SysFont('Verdana', 16))
fonts.append(pygame.font.SysFont('Verdana', 32))
fonts.append(pygame.font.SysFont('Verdana', 48))
fonts.append(pygame.font.SysFont('Verdana', 64))

window.fill((0,0,0))
drawText(window, "PONG", "c", fonts[3], (255,255,255))
pygame.display.flip()
pygame.time.wait(1500)

newGame()
while True:
	"""The main loop for the game. This will repeat until the end of the program."""
	#Handle Keyboard input and events
	for event in pygame.event.get(): #gets a list of events since the last time event.get() was called
		if event.type == QUIT:
			exit()
		elif event.type == KEYDOWN: #when a key is pressed
			keys[event.key] = True #set the key's value in our list to True (down)
			if event.key == K_ESCAPE:
				exit()
			if event.key == K_F1:
				newGame()
		elif event.type == KEYUP:
			keys[event.key] = False #set the key's value in our list to False (up)
	#Update paddles
	paddle1.update()
	paddle2.update()
	#Update ball
	ball.update()
	#Draw board lines
	pygame.draw.line(window, (255,255,255), (WINDOW_WIDTH/2,0),(WINDOW_WIDTH/2,WINDOW_HEIGHT))
	#Draw Scores
	drawText(window, str(SCORE1), (WINDOW_WIDTH/2 + 8,WINDOW_HEIGHT/2 - fonts[1].size(str(SCORE1))[1]/2), fonts[1])
	drawText(window, str(SCORE2), (WINDOW_WIDTH/2 - fonts[0].size(str(SCORE2))[1]-8,WINDOW_HEIGHT/2 - fonts[1].size(str(SCORE2))[1]/2), fonts[1])
	#Draw paddles
	paddle1.draw()
	paddle2.draw()
	#Draw ball
	ball.draw()
	#Refresh screen
	pygame.display.flip()
	window.fill((0,0,0)) #Fills the window with the color black
	
	clock.tick(FRAMERATE)
